package cn.iocoder.yudao.module.wecom.http;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.Map;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 封装一下企微api的各个接口请求
 */
@Slf4j
public class WeApi {
    private String accessToken;
    private String body;

    /**
     * 数据与智能专区 程序ID
     */
    private static final String PROGRAM_ID = "progIlPRuKxvHmo5YA7YSK8dGWoZb6z4fUOD";


    /**
     * 会话模型： 会话摘要模型id
     */
    private static final String CREATE_SUMMARY_TASK_PROGRAM_ID = "prog60cx1Ar6QCPbIgIOEAQMbSNA-grUMWD7";
    /**
     * 数据与智能专区 会话存档私钥
     */
    private static final String PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\n" +
            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCIGxnigz4H6Qoi\n" +
            "dd1veUixysHfbuIFAxXo9CXsclmQcS0F0F9jUadKaU7Ybc60GJt4CGEqRcgFT1+L\n" +
            "fa2x6PoddXD0MIgsyhMwCDjC28qpEUJNGHivnITy5D/YliV7BIjGsZXsAOVmiDqS\n" +
            "Rd6wMwurZLeYyq/2/ZgcN372BNH0lOWLOEestQ/4G9x0ZB2iyi93KuEbh+ACocjv\n" +
            "BiJyP/JA1SvCC1i6a8T2L+sac1SyBtybMCyJ8PWwlhCJmr8aR8nHSaH6XUabZ72B\n" +
            "9bhOTfECP00XCxXqLSqwTcf1R8xDcgIYx0lD6ZVHKP2E8sEJn2QilfIhK4L8sipw\n" +
            "22EePCuBAgMBAAECggEAL7F3d5VPxkvV/k9ZAff5DjwjhZ0AXItBQTlUlK9ZTTEr\n" +
            "eq8SzeXN/lg6hcKsvRUmXYBqM/rx5VJ0A5hNplsiUfJWW2sqPK+u25T19uo38NiY\n" +
            "aBWcLMVnHQn4iXfLuHjVSPLvuxxxRmWUSK9tIkcw3qVTZJoZ4S3qAHE97w2vWMnV\n" +
            "Z9PstCvSfcX8SyOzH+vPQGSC/ptwgFFFNZ6Zp0san3HPB+84D3H8Zeo+FxDIlO+t\n" +
            "BCUD84of/fg0aqC7JvRhT+KpjVv5/3wW5xl+tbMvtx+AYIsSps3xjirC5RpfXDKW\n" +
            "02Dn75bdq9useT2tEjMZ9sIraeNIfr77qcteDhnLFQKBgQDAiHYofjACBICBuVoA\n" +
            "mQwsCqGgFEbBpEA2XLKLFlYgTGPe6nbNFFhmLGmp60HdGoOpVdzYtXMSTEDHC2Sr\n" +
            "WptT7koxw1CyJRbxXVyKACm/MbsikJ3ypKqZyL5SgXplpCxfhY88FlNZ+s+dPwlE\n" +
            "gA6PQywjFNSLs3BIx9aw2LYJlwKBgQC0+Ng1w+lLsL1MKNpEDuSgQ/7mO0CMhNHm\n" +
            "JRWKsmASmoi0U4Z/9XeICN9qDBpF+lerk1Wq1ye2gu45nvjHsYtCqr9ejqxGCPsg\n" +
            "F4d4RBwhYTq4stJGpMIGL2Ept+vOSV7n7GPVv2h9rx9T7xJ406CMK8Km0QzSAkml\n" +
            "i3daNVympwKBgGRvy5PcIBctWgxSMM1XCa5/7UigyziBAq5ZNRqxkERRFVhYX5kk\n" +
            "H+lNCeIGQ9mf10ci745tOZY2CSTMoLtzDMx/5lyHUzVbe9h1p6yl4SFIRCMH5h2K\n" +
            "ISUQP5iyyrLzLeK2vb3Ot7SczmltVNxTIUVC+Wdjmm02MkEFXs3qfywJAoGAUATg\n" +
            "BRX1KASkDvLZX9J+AOdP5Bk692cbMHohRkyM8mzmGWX9SMMO8VWLA+cKDvscnL7u\n" +
            "2DV+V9MY5t2F/zZf70B0kajgP69k6tG8ks766T+GqXhYReg/6mA0xC+Q0ovarQ33\n" +
            "LuINn9U5MvG45zgb+x62WPCCjLF6Qvqh8X860m0CgYEAhAhVYy4fuxm/BPPt6v0p\n" +
            "0eODgOUX3CbztSy8+s+fjrWbjP5jeTIqCuW7LwCv1W6Hdy+B5sCb6P+nTu+gRdZy\n" +
            "CMI9x5MR/MrdbO852NoyVME4MtD0HRse+aZONcS0eB5AJcdHU+s38ZgAeKqi9Mw9\n" +
            "dSHK1q/7TcSrrZ9hhEB38zM=\n" +
            "-----END RSA PRIVATE KEY-----";

    /**
     * 数据与智能专区 会话存档公钥
     */
    private static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" +
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiBsZ4oM+B+kKInXdb3lI\n" +
            "scrB327iBQMV6PQl7HJZkHEtBdBfY1GnSmlO2G3OtBibeAhhKkXIBU9fi32tsej6\n" +
            "HXVw9DCILMoTMAg4wtvKqRFCTRh4r5yE8uQ/2JYlewSIxrGV7ADlZog6kkXesDML\n" +
            "q2S3mMqv9v2YHDd+9gTR9JTlizhHrLUP+BvcdGQdosovdyrhG4fgAqHI7wYicj/y\n" +
            "QNUrwgtYumvE9i/rGnNUsgbcmzAsifD1sJYQiZq/GkfJx0mh+l1Gm2e9gfW4Tk3x\n" +
            "Aj9NFwsV6i0qsE3H9UfMQ3ICGMdJQ+mVRyj9hPLBCZ9kIpXyISuC/LIqcNthHjwr\n" +
            "gQIDAQAB\n" +
            "-----END PUBLIC KEY-----";

    public WeApi(String token) {
        this.accessToken = token;
    }

    public WeApi() {

    }

    public WeApi token(String token) {
        this.accessToken = token;
        return this;
    }

    public WeApi body(Map<String, Object> map) {
        return body(JSONUtil.toJsonStr(map));
    }

    public WeApi body(String body) {
        this.body = body;
        return this;
    }

    public JSONObject execPost(String url) {
        String respStr = HttpUtil.createPost(url)
                .body(this.body)
                .execute()
                .body();
        JSONObject respJson = JSONUtil.parseObj(respStr);
//        log.info("WeApi url: {}", url);
//        log.info(this.body);
//        log.info(respJson.toString());
        this.checkErrCode(respJson);
        return respJson;
    }

    public JSONObject execGet(String url) {
        String respStr = HttpUtil.createGet(url)
                .execute()
                .body();
        JSONObject respJson = JSONUtil.parseObj(respStr);
//        log.info("WeApi url: {}", url);
//        log.info(respJson.toString());
        this.checkErrCode(respJson);
        return respJson;
    }

    /**
     * 获取企业应用永久授权码
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getPermanentCode() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取企微员工列表
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getUserList() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取企微客户群列表
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getChatGroupList() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/list?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取企微客户群详情
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getChatGroupInfo() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取企业获客链接列表
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getAcqLinkList() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/list_link?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取获客链接详情信息
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getAcqLinkDetailInfo() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/get?access_token=" + this.accessToken;
        return execPost(url);
    }


    /**
     * 获取通过获客链接加入的客户列表
     *
     * @return
     * @author PetePower
     * @since 2024-08-06
     */
    public JSONObject getAcqLinkCustomerList() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/customer?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 查询获客链接最近30天的使用情况
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject getAcqLinkUseStat() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/statistic?access_token=" + this.accessToken;
        return execPost(url);
    }


    /**
     * 创建获客链接
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject createAcqLink() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/create_link?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 编辑获客链接
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject updateAcqLink() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/update_link?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 删除获客链接
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject deleteAcqLink() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/delete_link?access_token=" + this.accessToken;
        return execPost(url);
    }


    // ==================== 群发消息模块 ===================

    /**
     * 创建企业群发
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject sendMsgTemplate() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 查询成员群发结果（指定群发msgid）
     *
     * @return
     * @author PetePower
     * @since 2024-08-07
     */
    public JSONObject getMsgSendResult() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_send_result?access_token=" + this.accessToken;
        return execPost(url);
    }

    // ============================  发表朋友圈模块 ============================== //
    public JSONObject addMomentTask() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_moment_task?access_token=" + this.accessToken;
        return execPost(url);
    }

    // ============================ 客户标签 ========================== //

    /**
     * 获取企微标签库
     * @since 2024-08-26
     * @author PetePower
     * @return
     */
    public JSONObject getCorpTag() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 添加标签/组
     * @link <a href="https://developer.work.weixin.qq.com/document/path/92696#%E6%B7%BB%E5%8A%A0%E4%BC%81%E4%B8%9A%E5%AE%A2%E6%88%B7%E6%A0%87%E7%AD%BE">...</a>
     * @since 2024-08-26
     * @author PetePower
     * @return
     */
    public JSONObject addCorpTag() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_corp_tag?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 编辑标签
     * @since 2024-08-26
     * @author PetePower
     * @return
     */
    public JSONObject editCorpTag() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/edit_corp_tag?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 删除企微标签
     * @since 2024-08-26
     * @author PetePower
     * @return
     */
    public JSONObject delCorpTag() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_corp_tag?access_token=" + this.accessToken;
        return execPost(url);
    }

    public JSONObject markTag() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag?access_token=" + this.accessToken;
        return execPost(url);
    }

    // ================================ 数据与智能专区 ==================================== //

    /**
     * 设置企业数据与智能专区回调事件
     * postData: program_id 程序id
     * @since 2024-08-30
     * @author PetePower
     * @return
     */
    public JSONObject setDataReceiveCallback() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/set_receive_callback?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.of("program_id", PROGRAM_ID));
        return execPost(url);
    }

    /**
     * 设置企业会话存档加解密公钥
     * @since 2024-08-30
     * @author PetePower
     * @return
     */
    public JSONObject setDataPublicKey() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/set_public_key?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("public_key", PUBLIC_KEY)
                .put("public_key_ver", 1)
                .build());
        return execPost(url);
    }

    /**
     * 应用同步调用专区程序
     * @since 2024-08-30
     * @author PetePower
     * @return
     */
    public JSONObject syncCallProgramGetCallbackData(String notifyId) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/sync_call_program?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", "get_callback_data")
                .put("notify_id", notifyId)
                .put("request_data", JSONUtil.toJsonStr(MapUtil.of("notify_id", notifyId)))
                .build()
        );
        return execPost(url);
    }

    public JSONObject syncCallProgram(String ability_id, String requestData) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/sync_call_program?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", ability_id)
                .put("request_data", requestData)
                .build()
        );
        return execPost(url);
    }

    // ================================= 异步任务 -- 应用调用专区： 调用会话摘要模型 ================================== //
    // ================================= 调用异步任务流程如下：
    // ================================= 1. 应用异步调用专区程序：async_program_task -> 能力id -> 返回jobid
    // ================================= 2. 专区程序调用sdk -> 模型id -> 返回jobid2
    // ================================= 3. loop jobid2 去查询任务状态 -> 任务执行完毕 -> 调用上报异步任务结果：program_async_job_result

    /**
     * 第一步：应用异步调用专区程序
     * @param abId
     * @param requestData
     * @since 2024-11-01
     * @author PetePower
     * @return
     */
    public JSONObject asyncCallProgramJob(String abId, String requestData) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/async_program_task?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", abId)
                .put("request_data", requestData)
                .build()
        );
        return execPost(url);
    }

    /**
     * 第二步： 专区程序调用sdk
     * @param ability_id sdk能力id
     * @param requestData 请求包
     * @since 2024-11-01
     * @author PetePower
     * @return
     */
    public JSONObject syncCallSDKTask(String ability_id, String requestData) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/sync_call_program?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", ability_id)
                .put("request_data", requestData)
                .build()
        );
        return execPost(url);
    }

    public JSONObject asyncCallProgramJobResult(String jobid) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/async_program_result?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("jobid", jobid)
                .build()
        );
        return execPost(url);
    }

    public JSONObject programAsyncJobCallBack(String data) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/async_program_task?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", "invoke_program_async_job_call_back")
                .put("request_data", data)
                .build()
        );
        return execPost(url);
    }
    /**
     * 应用获取会话记录
     * @since 2024-08-30
     * @author PetePower
     * @return
     */
    public JSONObject syncCallProgramSyncMsg(String queryCursor, String token) {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/chatdata/sync_call_program?access_token=" + this.accessToken;
        this.body = JSONUtil.toJsonStr(MapUtil.builder()
                .put("program_id", PROGRAM_ID)
                .put("ability_id", "invoke_sync_msg")
                .put("request_data", JSONUtil.toJsonStr(MapUtil.builder()
                        .put("cursor", queryCursor)
                        .put("token", token)
                        .build()
                ))
                .build()
        );
        return execPost(url);
    }

    // ================================ 数据统计 ==================================== //

    /**
     * 查询客户联系统计数据
     * @since 2024-09-02
     * @author PetePower
     * @return
     */
    public JSONObject getContactStat() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_user_behavior_data?access_token=" + this.accessToken;
        return execPost(url);
    }

    /**
     * 获取群聊数据统计数据
     * @since 2024-09-02
     * @author PetePower
     * @return
     */
    public JSONObject getChatStat() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/statistic?access_token=" + this.accessToken;
        return execPost(url);
    }

    // ================================ 用户授权登录组件 =============================================== //
    public JSONObject weUserLogin(String code) {
        // https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?suite_access_token=SUITE_ACCESS_TOKEN&code=CODE
        String url = "https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd?debug=1&suite_access_token="+this.accessToken+"&code="+code;
        return execGet(url);
    }

    // ================================ 数据与智能专区 - 会话展示组件 ==================================== //

    /**
     * 获取 企业 Jsapi Ticket
     * @since 2024-08-31
     * @author PetePower
     * @return
     */
    public JSONObject getJsApiTicket() {
        String url = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?type=agent_config&access_token=" + this.accessToken;
        return execPost(url);
    }


    public String uploadFile(String name, File file, String filename) {
        String res = HttpUtil.createPost("https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + this.accessToken)
                .form(name, file, filename)
                .execute().body();
        JSONObject result = JSONUtil.parseObj(res);
        checkErrCode(result);
        log.info("upload file res:L +====== {}", res);
        return result.getStr("url");
    }

    /**
     * 上传附件内容
     * @param name  字段名称： media
     * @param file  文件
     * @param filename  文件名称
     * @param mediaType 媒体文件类型，分别有图片（image）、视频（video）、普通文件（file）
     * @param attachmentType 附件类型，不同的附件类型用于不同的场景。1：朋友圈；2:商品图册
     * @since 2024-08-26
     * @author PetePower
     * @return
     */
    public String uploadAttach(String name, File file, String filename, String mediaType, int attachmentType) {
        String res = HttpUtil.createPost(
                        "https://qyapi.weixin.qq.com/cgi-bin/media/upload_attachment?access_token=" + this.accessToken + "&media_type=" + mediaType + "&attachment_type=" + attachmentType)
                .form(name, file, filename)
                .execute().body();
        JSONObject result = JSONUtil.parseObj(res);
        checkErrCode(result);
        return result.getStr("media_id");
    }

    public String decryptMsg(String encrypt_key) {
        String pk = PRIVATE_KEY.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "").replace("\n", "");
        RSA rsa = new RSA(pk, null);
//         加载密钥
        try {
            return rsa.decryptStr(encrypt_key, KeyType.PrivateKey);
        } catch (Exception e) {
            log.error("消息解密失败: {}", e.getMessage());
            return null;
        }
    }

    public void checkErrCode(JSONObject respJson) {
        Integer errCode = respJson.getInt("errcode");
        if (Objects.isNull(errCode)) {
            return;
        }
        log.debug("WeAPI 返回json === {}", respJson);
        if (ObjectUtil.equal(40014, errCode)) {
//            log.error("WeAPI返回错误码： {}", respJson.getStr("errmsg"));
            throw exception(new ErrorCode(100500, "应用已失效或未授权，请刷新后重试"));
        }
        if (ObjectUtil.equal(710642, errCode)) {
//            log.error("WeAPI返回错误码： {}", respJson.getStr("errmsg"));
            throw exception(new ErrorCode(710642, "模型数据分析尚未完成"));
        }
        if (ObjectUtil.notEqual(0, errCode)) {
            log.error("WeAPI 返回json === {}", respJson);
            log.error("WeAPI返回错误码： {}", respJson.getStr("errmsg"));
            throw exception(new ErrorCode(100500, "接口返回错误,状态码错误"));
        }
    }
}
